#region Usings

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using GateShift.Common.Controls.Wizards.Design;
using GateShift.Common.Controls.Wizards.Pages;

#endregion

namespace GateShift.Common.Controls.Wizards
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(WizardForm), "GateShift.Common.Controls.ToolboxIcons.WizardForm.bmp")]
    [Designer(typeof(WizardFormDesigner))]
    public partial class WizardForm : UserControl
    {
        #region Class Constants and Enumerators

        // static constants of Text displayed on Buttons. This values can be 
        // replaced by Wizard user in case of localization
        public static string DEF_FINISH = "&Finish";
        public static string DEF_NEXT = "&Next >";
        public static string DEF_BACK = "< &Back";
        public static string DEF_CANCEL = "&Cancel";
        #endregion

        #region Class Members
        private WizardsButtons m_eButtons = WizardsButtons.All;          // wizard buttons

        private int m_iShowIndex = 0;           // Index of Shown Wizard page
        private int m_iLastShown = -1;
        private WizardPageBase m_CurrentPage;   // Currently Shown Wizard Page
        #endregion

        #region Class Events
        [Category("Property Changed")]
        public event EventHandler WizardButtonsChanged;

        [Category("Wizard")]
        public event EventHandler<EventNextArgs> Next;

        [Category("Wizard")]
        public event EventHandler<EventNextArgs> Finish;

        [Category("Wizard")]
        public event EventHandler<EventNextArgs> Back;

        [Category("Wizard")]
        public event EventHandler Cancel;

        [Category("Wizard")]
        public event EventHandler<EventNextArgs> PageShown;

        #endregion

        #region Class Properties
        [Browsable(true)]
        [Category("Wizard")]
        [Description("Gets or sets buttons states in wizard control for current Wizard Page")]
        [DefaultValue(typeof(WizardsButtons), "All")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        // [Editor(FlagsEditor, typeof(UITypeEditor))]
        public WizardsButtons WizardButtons
        {
            get { return m_eButtons; }
            set
            {
                if (value != m_eButtons)
                {
                    m_eButtons = value;
                    OnWizardButtonChanged();
                }
            }
        }

        [Browsable(true)]
        [Category("Wizard")]
        [Description("Gets collection of wizard pages")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public WizardPagesCollection Pages { get; private set; }

        [Browsable(true)]
        [Category("Wizard")]
        [Description("Gets or sets Current page of wizard")]
        public int PageIndex
        {
            get { return m_iShowIndex; }
            set
            {
                if (value != m_iShowIndex &&
                    value < Pages.Count &&
                    value >= 0)
                {
                    m_iShowIndex = value;
                    ShowWizardPage();
                }
            }
        }
        #endregion

        /// <summary>
        /// Default Constructor
        /// </summary>
        public WizardForm()
        {
            InitializeComponent();

            Pages = new WizardPagesCollection(this);
            Pages.Changed += new EventHandler(PagesCollectionChanged);

            btnBack.Text = DEF_BACK;
            btnNextFinish.Text = DEF_NEXT;
            btnCancel.Text = DEF_CANCEL;

            this.Paint += new PaintEventHandler(WizardForm_Paint);
            this.Resize += new EventHandler(WizardForm_Resize);
            this.pnlHeader.Paint += new PaintEventHandler(pnlHeader_Paint);
        }

        void pnlHeader_Paint(object sender, PaintEventArgs e)
        {
            ControlPaint.DrawBorder3D(e.Graphics, new Rectangle(0, pnlHeader.Bottom - 2, Width, 2),
                                      Border3DStyle.Etched, Border3DSide.Bottom);
        }

        void WizardForm_Resize(object sender, EventArgs e)
        {
            ChangeButtonsStates();
        }

        void WizardForm_Paint(object sender, PaintEventArgs e)
        {
            ControlPaint.DrawBorder3D(e.Graphics, new Rectangle(0, pnlMain.Bottom, Width, 2),
                                      Border3DStyle.Etched, Border3DSide.Bottom);
        }


        #region Windows Form Designer generated code
        //// <summary>
        //// Control Initialization and Designer View Code
        //// </summary>
        // private void InitializeComponent()
        // {

        // 
        // lineDownLimit
        // 
        // this.lineDownLimit.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
        //  | System.Windows.Forms.AnchorStyles.Right);
        // this.lineDownLimit.Location = new System.Drawing.Point(4, 333);
        // this.lineDownLimit.Name = "lineDownLimit";
        // this.lineDownLimit.Size = new System.Drawing.Size(488, 4);
        // this.lineDownLimit.TabIndex = 0;
        // this.lineDownLimit.Text = "lineFrame1";
        // 
        // pnlBody
        // 


        // }
        #endregion



        #region Designer Helper functions
        /// <summary>
        /// Special Method Used only In Designer Control Mode
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void WizardPageAttributesChanged(object sender, EventArgs e)
        {
            WizardPageBase page = (WizardPageBase)sender;

            // remove designer event first
            page.Changed -= new EventHandler(WizardPageAttributesChanged);

            m_iLastShown = -1;
            ShowWizardPage();
        }

        /// <summary>
        /// Method Indicate is Point on "Back" or "Next" Buttons. Method used only by Designer
        /// </summary>
        /// <param name="p">Point coordinates to check</param>
        /// <returns>TRUE - poin found on Butons</returns>
        public bool OnDesignedWizardButtons(Point p)
        {
            Rectangle rect1 = new Rectangle(btnNextFinish.Location, btnNextFinish.Size);
            Rectangle rect2 = new Rectangle(btnBack.Location, btnBack.Size);

            return (rect1.Contains(p) || rect2.Contains(p));
        }

        public Rectangle GetCurrentPageRect()
        {
            if (m_CurrentPage != null)
            {
                if (m_CurrentPage.WelcomePage == true)
                {
                    return pnlMain.ClientRectangle;
                }
                else
                {
                    return pnlBody.ClientRectangle;
                }
            }

            return Rectangle.Empty;
        }
        #endregion



        #region Handled Events

        protected virtual void PagesCollectionChanged(object sender, EventArgs e)
        {
            if (Pages.Count > 0)
            {
                m_iLastShown = -1;
                ShowWizardPage();
            }
        }

        #endregion

        #region Helper Methods

        protected void ShowWizardPage()
        {
            // do not show one page twice
            if (m_iShowIndex == m_iLastShown)
                return;

            pnlMain.SuspendLayout();
            pnlBody.SuspendLayout();

            pnlMain.Controls.Clear();
            pnlBody.Controls.Clear();

            // check if control has any pages
            if (Pages.Count > 0)
            {
                Pages.Sort();

                // check m_iShowIndex
                if (m_iShowIndex < 0) m_iShowIndex = 0;
                if (m_iShowIndex >= Pages.Count) m_iShowIndex = Pages.Count - 1;

                m_CurrentPage = Pages[m_iLastShown = m_iShowIndex];

                // set page parent correctly in case when is something wrong
                if (m_CurrentPage.WizardPageParent != this)
                    m_CurrentPage.WizardPageParent = this;

                // show page custom data
                if (m_CurrentPage.HeaderImage != null)
                {
                    imgHeader.Image = m_CurrentPage.HeaderImage;
                }
                else
                {
                    if (m_CurrentPage.ImageList != null &&
                        m_CurrentPage.ImageIndex >= 0 &&
                        m_CurrentPage.ImageIndex < m_CurrentPage.ImageList.Images.Count)
                        imgHeader.Image = m_CurrentPage.ImageList.Images[m_CurrentPage.ImageIndex];
                    else
                        imgHeader.Image = null;
                }

                lblTitle.Text = m_CurrentPage.Title;
                lblDescription.Text = m_CurrentPage.Description;

                m_CurrentPage.Changed -= WizardPageAttributesChanged;
                m_CurrentPage.Changed += new EventHandler(WizardPageAttributesChanged);

                // if Welcome page then link it ot pnlMain otherwise to pnlBody
                if (m_CurrentPage.WelcomePage == false)
                {
                    pnlMain.Controls.AddRange(new System.Windows.Forms.Control[] { pnlBody, pnlHeader });

                    // fix width and height of body panel
                    pnlBody.Width = pnlMain.Width - 16;
                    pnlBody.Height = pnlMain.Height - pnlHeader.Height - 8;

                    // fix page control resize
                    if (m_CurrentPage.Width != pnlBody.Width ||
                        m_CurrentPage.Height != pnlBody.Height)
                    {
                        m_CurrentPage.Width = pnlBody.Width;
                        m_CurrentPage.Height = pnlBody.Height;
                    }

                    pnlBody.Controls.Add(m_CurrentPage);
                    pnlBody.Controls[0].Focus();
                }
                else
                {
                    // fix page control resize
                    if (m_CurrentPage.Width != pnlMain.Width ||
                        m_CurrentPage.Height != pnlMain.Height)
                        m_CurrentPage.Size = pnlMain.Size;

                    pnlMain.Controls.Add(m_CurrentPage);
                    pnlMain.Controls[0].Focus();
                }

                // if current page has indicator that it is a Finish Page then Show 
                // Finish Button
                if (m_CurrentPage.FinishPage == true)
                    m_eButtons |= WizardsButtons.Finish;
                else // otherwise do not show Finish Button
                    m_eButtons &= (~WizardsButtons.Finish);

                // modify buttons states
                ChangeButtonsStates();
            }
            else // in case of empty Collection show standard "work page" view of control
            {
                pnlMain.Controls.AddRange(new System.Windows.Forms.Control[] { pnlBody, pnlHeader });
            }

            pnlBody.ResumeLayout();
            pnlMain.ResumeLayout();

            OnPageShown(new EventNextArgs(m_CurrentPage, Pages.IndexOf(m_CurrentPage)));
        }

        protected void ChangeButtonsStates()
        {
            int iNewWidth = Width;
            bool bFinish = ((m_eButtons & WizardsButtons.Finish) == WizardsButtons.Finish);

            // Cancel Button
            btnCancel.Left = iNewWidth - btnCancel.Width - 8;
            btnCancel.Top = pnlMain.Bottom + 14;
            btnCancel.Enabled = ((m_eButtons & WizardsButtons.Cancel) == WizardsButtons.Cancel);
            iNewWidth = btnCancel.Left;

            // Next or Finish Button
            btnNextFinish.Left = iNewWidth - btnNextFinish.Width - 8;
            btnNextFinish.Top = btnCancel.Top;
            btnNextFinish.Enabled = ((m_eButtons & WizardsButtons.Next) == WizardsButtons.Next);
            btnNextFinish.Text = (bFinish == true) ? DEF_FINISH : DEF_NEXT;
            btnNextFinish.DialogResult = (bFinish == true) ? DialogResult.OK : DialogResult.None;
            iNewWidth = btnNextFinish.Left;

            // Back button
            btnBack.Left = iNewWidth - btnBack.Width;
            btnBack.Top = btnCancel.Top;
            btnBack.Enabled = ((m_eButtons & WizardsButtons.Previous) == WizardsButtons.Previous);

            if (m_CurrentPage != null)
                if (m_CurrentPage.Index <= 0 && btnBack.Enabled)
                    btnBack.Enabled = false;

        }

        #endregion

        #region Navigational Methods

        public void PageNext()
        {
            PageNext(1);
        }

        public void PagePrevious()
        {
            PagePrevious(1);
        }

        public void PageNext(int count)
        {
            if (count == 0)
                return;

            m_iShowIndex += count;
            ShowWizardPage();
        }

        public void PagePrevious(int count)
        {
            if (count <= 0)
                return;

            m_iShowIndex -= count;
            ShowWizardPage();
        }

        public void PageFirst()
        {
            m_iShowIndex = 0;
            ShowWizardPage();
        }

        public void PageLast()
        {
            m_iShowIndex = Pages.Count - 1;
            ShowWizardPage();
        }

        #endregion

        #region Event Raisers

        protected void OnWizardButtonChanged()
        {
            if (WizardButtonsChanged != null)
                WizardButtonsChanged(this, EventArgs.Empty);

            ChangeButtonsStates();
        }

        protected void OnNext(EventNextArgs e)
        {
            if (Next != null)
                Next(m_CurrentPage, e);

            PageNext(e.Step);
        }

        protected void OnFinish(EventNextArgs e)
        {
            if (Finish != null)
                Finish(this, e);
        }

        protected void OnBack(EventNextArgs e)
        {
            if (Back != null)
                Back(this, e);

            PagePrevious(e.Step);
        }

        protected void OnCancel()
        {
            if (Cancel != null)
                Cancel(this, EventArgs.Empty);
        }

        protected void OnPageShown(EventNextArgs e)
        {
            if (PageShown != null)
                PageShown(this, e);
        }

        #endregion

        #region Button Events Handlers

        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (btnCancel.Visible && btnCancel.Enabled)
                OnCancel();
        }

        private void btnNextFinish_Click(object sender, EventArgs e)
        {
            if (!btnNextFinish.Visible || !btnNextFinish.Enabled)
                return;

            if (m_CurrentPage != null)
            {
                if (m_CurrentPage.FinishPage && DesignMode)
                    OnFinish(new EventNextArgs(m_CurrentPage));
                else
                    OnNext(new EventNextArgs(m_CurrentPage));
            }
            else
                btnNextFinish.Enabled = false;
        }

        private void btnBack_Click(object sender, EventArgs e)
        {
            if (btnBack.Visible && btnBack.Enabled)
                OnBack(new EventNextArgs(m_CurrentPage));
        }

        #endregion
    }
}